<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <p data-lake-id="ueac44023" id="ueac44023"><span data-lake-id="uc89c79a4" id="uc89c79a4">为什么要把String设计成不可变的呢？有什么好处呢？</span></p>
  <p data-lake-id="uee82ad7f" id="uee82ad7f"><br></p>
  <p data-lake-id="ue9504466" id="ue9504466"><span data-lake-id="u54bf4da1" id="u54bf4da1">这个问题，困扰过很多人，甚至有人直接问过Java的创始人James Gosling。</span></p>
  <p data-lake-id="uf61d00a2" id="uf61d00a2"><br></p>
  <p data-lake-id="u25b76977" id="u25b76977"><span data-lake-id="u41472308" id="u41472308">在一次采访中James Gosling被问到什么时候应该使用不可变变量，他给出的回答是:</span></p>
  <p data-lake-id="u392092b1" id="u392092b1"><br></p>
  <blockquote data-lake-id="u8000de87" id="u8000de87">
   <p data-lake-id="u27e6561f" id="u27e6561f"><span data-lake-id="u81a0e539" id="u81a0e539">I would use an immutable whenever I can.</span></p>
  </blockquote>
  <p data-lake-id="u4f0f39b2" id="u4f0f39b2"><br></p>
  <p data-lake-id="uf9f6a52c" id="uf9f6a52c"><span data-lake-id="ue7fd224d" id="ue7fd224d">那么，他给出这个答案背后的原因是什么呢？是基于哪些思考的呢？</span></p>
  <p data-lake-id="u84283c3a" id="u84283c3a"><br></p>
  <p data-lake-id="ud4e52755" id="ud4e52755"><span data-lake-id="ue8df1716" id="ue8df1716">其实，主要是从缓存、安全性、线程安全和性能等角度出发的。</span></p>
  <p data-lake-id="u3bf1889c" id="u3bf1889c"><br></p>
  <h3 data-lake-id="BAuGt" id="BAuGt"><span data-lake-id="u490e7245" id="u490e7245">缓存</span></h3>
  <p data-lake-id="u5341e016" id="u5341e016"><br></p>
  <p data-lake-id="udbdd5bc4" id="udbdd5bc4"><span data-lake-id="u47780246" id="u47780246">字符串是使用最广泛的数据结构。大量的字符串的创建是非常耗费资源的，所以，Java提供了对字符串的缓存功能，可以大大的节省堆空间。</span></p>
  <p data-lake-id="u7703aaad" id="u7703aaad"><br></p>
  <p data-lake-id="ub1d34d6c" id="ub1d34d6c"><span data-lake-id="uae2370b1" id="uae2370b1">JVM中专门开辟了一部分空间来存储Java字符串，那就是字符串池。</span></p>
  <p data-lake-id="uc797382f" id="uc797382f"><br></p>
  <p data-lake-id="ube75d5e4" id="ube75d5e4"><span data-lake-id="u480e8d2b" id="u480e8d2b">通过字符串池，两个内容相同的字符串变量，可以从池中指向同一个字符串对象，从而节省了关键的内存资源。</span></p>
  <p data-lake-id="u9d264884" id="u9d264884"><br></p>
  <pre lang="java"><code>
String s = "abcd";
String s2 = s;
</code></pre>
  <p data-lake-id="ua89bdd0f" id="ua89bdd0f"><br></p>
  <p data-lake-id="udb4149f8" id="udb4149f8"><span data-lake-id="u38147e04" id="u38147e04">对于这个例子，s和s2都表示"abcd"，所以他们会指向字符串池中的同一个字符串对象：</span></p>
  <p data-lake-id="ubee19fb7" id="ubee19fb7"><br></p>
  <p data-lake-id="u00776fa4" id="u00776fa4"><img src="https://cdn.nlark.com/yuque/0/2022/jpeg/5378072/1672212318617-14a7ca77-145c-41eb-b2b0-936539bc1ad9.jpeg?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_19%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"><span data-lake-id="u1167c2d2" id="u1167c2d2">​</span></p>
  <p data-lake-id="u729cebd0" id="u729cebd0"><br></p>
  <p data-lake-id="u571ac93b" id="u571ac93b"><span data-lake-id="u3dab417e" id="u3dab417e">但是，之所以可以这么做，主要是因为字符串的不变性。试想一下，如果字符串是可变的，我们一旦修改了s的内容，那必然导致s2的内容也被动的改变了，这显然不是我们想看到的。</span></p>
  <p data-lake-id="u0729288f" id="u0729288f"><br></p>
  <h3 data-lake-id="TkAIK" id="TkAIK"><span data-lake-id="u29ddbd08" id="u29ddbd08">安全性</span></h3>
  <p data-lake-id="u6aefee01" id="u6aefee01"><br></p>
  <p data-lake-id="u0a976c0f" id="u0a976c0f"><span data-lake-id="u0cc0a557" id="u0cc0a557">字符串在Java应用程序中广泛用于存储敏感信息，如用户名、密码、连接url、网络连接等。JVM类加载器在加载类的时也广泛地使用它。</span></p>
  <p data-lake-id="uccb0e705" id="uccb0e705"><br></p>
  <p data-lake-id="u40fcd681" id="u40fcd681"><span data-lake-id="u95166ac1" id="u95166ac1">因此，保护String类对于提升整个应用程序的安全性至关重要。</span></p>
  <p data-lake-id="u569a90c6" id="u569a90c6"><br></p>
  <p data-lake-id="uf49d1762" id="uf49d1762"><span data-lake-id="ud9832417" id="ud9832417">当我们在程序中传递一个字符串的时候，如果这个字符串的内容是不可变的，那么我们就可以相信这个字符串中的内容。</span></p>
  <p data-lake-id="u5d6ec7da" id="u5d6ec7da"><br></p>
  <p data-lake-id="uf59fc453" id="uf59fc453"><span data-lake-id="u2837a31c" id="u2837a31c">但是，如果是可变的，那么这个字符串内容就可能随时都被修改。那么这个字符串内容就完全不可信了。这样整个系统就没有安全性可言了。</span></p>
  <p data-lake-id="u1fbb9c0b" id="u1fbb9c0b"><br></p>
  <h3 data-lake-id="w52IV" id="w52IV"><span data-lake-id="ub2a7df6f" id="ub2a7df6f">线程安全</span></h3>
  <p data-lake-id="ufa2d7eac" id="ufa2d7eac"><br></p>
  <p data-lake-id="udc54e6c2" id="udc54e6c2"><span data-lake-id="u664c7926" id="u664c7926">不可变会自动使字符串成为线程安全的，因为当从多个线程访问它们时，它们不会被更改。</span></p>
  <p data-lake-id="ud8876a02" id="ud8876a02"><br></p>
  <p data-lake-id="uccbd44d3" id="uccbd44d3"><span data-lake-id="uf3cafcfe" id="uf3cafcfe">因此，一般来说，不可变对象可以在同时运行的多个线程之间共享。它们也是线程安全的，因为如果线程更改了值，那么将在字符串池中创建一个新的字符串，而不是修改相同的值。因此，字符串对于多线程来说是安全的。</span></p>
  <p data-lake-id="u944db127" id="u944db127"><br></p>
  <h3 data-lake-id="IpVaE" id="IpVaE"><span data-lake-id="u2c3dc6c9" id="u2c3dc6c9">hashcode缓存</span></h3>
  <p data-lake-id="u906dacb2" id="u906dacb2"><br></p>
  <p data-lake-id="ud4ec844d" id="ud4ec844d"><span data-lake-id="u877236b6" id="u877236b6">由于字符串对象被广泛地用作数据结构，它们也被广泛地用于哈希实现，如HashMap、HashTable、HashSet等。在对这些散列实现进行操作时，经常调用hashCode()方法。</span></p>
  <p data-lake-id="ud3858228" id="ud3858228"><br></p>
  <p data-lake-id="ud7841be3" id="ud7841be3"><span data-lake-id="ub0080d56" id="ub0080d56">不可变性保证了字符串的值不会改变。因此，hashCode()方法在String类中被重写，以方便缓存，这样在第一次hashCode()调用期间计算和缓存散列，并从那时起返回相同的值。</span></p>
  <p data-lake-id="u38ee016f" id="u38ee016f"><br></p>
  <p data-lake-id="ubc461da9" id="ubc461da9"><span data-lake-id="u51c4bda2" id="u51c4bda2">在String类中，有以下代码：</span></p>
  <p data-lake-id="uf334cb13" id="uf334cb13"><br></p>
  <pre lang="java"><code>
private int hash;//this is used to cache hash code.
</code></pre>
  <p data-lake-id="u734c2009" id="u734c2009"><br></p>
  <h3 data-lake-id="JkxJg" id="JkxJg"><span data-lake-id="u45a4ce88" id="u45a4ce88">性能</span></h3>
  <p data-lake-id="u48d19bb8" id="u48d19bb8"><br></p>
  <p data-lake-id="u6abe3991" id="u6abe3991"><span data-lake-id="u7d7f4c7b" id="u7d7f4c7b">前面提到了的字符串池、hashcode缓存等，都是提升性能的体现。</span></p>
  <p data-lake-id="ucceeaf9b" id="ucceeaf9b"><br></p>
  <p data-lake-id="u8aad9359" id="u8aad9359"><span data-lake-id="ueee03d0d" id="ueee03d0d">因为字符串不可变，所以可以用字符串池缓存，可以大大节省堆内存。而且还可以提前对hashcode进行缓存，更加高效</span></p>
  <p data-lake-id="u474f4453" id="u474f4453"><br></p>
  <p data-lake-id="u0ea71ac0" id="u0ea71ac0"><span data-lake-id="u5c07c678" id="u5c07c678">由于字符串是应用最广泛的数据结构，提高字符串的性能对提高整个应用程序的总体性能有相当大的影响。</span></p>
  <p data-lake-id="uef133c43" id="uef133c43"><br></p>
 </body>
</html>